﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Windows.Data;
using Foundation;

namespace Poet.ViewModels
{
    [DataContract]
    class EncodingViewModel : ViewModel
    {
        public char[] OrSeparators { get; set; }

        public char[] AndSeparators { get; set; }

        public EncodingViewModel()
        {
            Initialize();
        }

        private static readonly List<EncodingInfo> AllEncodingInfos = Encoding.GetEncodings().ToList();

        public ObservableCollection<EncodingInfo> EncodingInfos { get; private set; }

        [DataMember]
        public EncodingInfo CurrentEncodingInfo
        {
            get { return Get(() => CurrentEncodingInfo); }
            set { if (value != null) Set(() => CurrentEncodingInfo, value); }
        }

        public Encoding CurrentEncoding
        {
            get { return CurrentEncodingInfo == null ? null : Encoding.GetEncoding(CurrentEncodingInfo.CodePage); }
        }

        [DataMember]
        public string Keywords
        {
            get { return Get(() => Keywords); }
            set { Set(() => Keywords, value); }
        }  
        
        private ICollectionView EncodingInfosDefaultView { get; set; }

        [OnDeserialized]
        private void Initialize(StreamingContext context = default(StreamingContext))
        {
            OrSeparators = new[] {',', '.', '|', '/'};
            AndSeparators = new[] {' ', '&', '+'};
            ApplicationClosing += () => this.TrySerializeDataContract();
            EncodingInfos = new ObservableCollection<EncodingInfo>(AllEncodingInfos);
            EncodingInfosDefaultView = CollectionViewSource.GetDefaultView(EncodingInfos);
            EncodingInfosDefaultView.Filter = item => IsMatch((EncodingInfo) item);
            this[() => Keywords].PropertyChanged +=
                (sender, args) =>
                    {
                        EncodingInfosDefaultView.Refresh();
                        var tmp = CurrentEncodingInfo;
                        Set(() => CurrentEncodingInfo, null);
                        Set(() => CurrentEncodingInfo, tmp);
                    };

            RaisePropertyChangedEvent(() => Keywords);
        }

        private bool IsMatch(EncodingInfo encodingInfo)
        {
            if (string.IsNullOrWhiteSpace(Keywords)) return true;
            var phrases =
                Keywords.Split(OrSeparators).Select(p => p.Trim()).Where(p => !string.IsNullOrWhiteSpace(p)).ToArray();
            if (!phrases.Any()) return true;
            return
                phrases.Select(phrase => phrase.Split(AndSeparators))
                       .Any(words => words.All(w => ContainsWord(encodingInfo, w)));
        }

        private static bool ContainsWord(EncodingInfo encodingInfo, string word)
        {
            return
                encodingInfo.CodePage.ToString(CultureInfo.InvariantCulture).ToLower().Contains(word) ||
                encodingInfo.DisplayName.ToLower().Contains(word) ||
                encodingInfo.Name.ToLower().Contains(word);
        }
    }
}
